gtkpopover: Add cascade-popdown property/functions
authorCarlos Garnacho <carlosg@gnome.org>
Tue, 13 Oct 2020 12:26:41 +0000 (14:26 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 13 Oct 2020 14:55:53 +0000 (16:55 +0200)
And honor it in gtk_popover_popdown(). By default, a GtkPopover
pops down automatically if a child popover was closed, if this
property is FALSE, the popover will remain opened.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkpopover.c
gtk/gtkpopover.h
gtk/gtkwidget.c

index 71ffac0806a36d7a00d73e9d26cc03258a3986a9..bf33adde326a712606b830efdf2b0bff68bc21e3 100644 (file)
@@ -6150,6 +6150,8 @@ gtk_popover_get_has_arrow
 gtk_popover_set_offset
 gtk_popover_get_offset
 gtk_popover_set_default_widget
+gtk_popover_set_cascade_popdown
+gtk_popover_get_cascade_popdown
 <SUBSECTION Standard>
 GTK_TYPE_POPOVER
 GTK_IS_POPOVER
index fd3567d8e275b95b2508763963873ded60d86814..c6fa5851d1d5847815ad68a7143cb86d2e39ee41 100644 (file)
@@ -149,6 +149,7 @@ typedef struct {
   gboolean has_arrow;
   gboolean mnemonics_visible;
   gboolean disable_auto_mnemonics;
+  gboolean cascade_popdown;
 
   int x_offset;
   int y_offset;
@@ -181,6 +182,7 @@ enum {
   PROP_HAS_ARROW,
   PROP_MNEMONICS_VISIBLE,
   PROP_CHILD,
+  PROP_CASCADE_POPDOWN,
   NUM_PROPERTIES
 };
 
@@ -852,6 +854,7 @@ gtk_popover_init (GtkPopover *popover)
   priv->final_position = GTK_POS_BOTTOM;
   priv->autohide = TRUE;
   priv->has_arrow = TRUE;
+  priv->cascade_popdown = TRUE;
 
   controller = gtk_event_controller_key_new ();
   g_signal_connect_swapped (controller, "key-pressed", G_CALLBACK (gtk_popover_key_pressed), popover);
@@ -1479,6 +1482,10 @@ gtk_popover_set_property (GObject      *object,
       gtk_popover_set_child (popover, g_value_get_object (value));
       break;
 
+    case PROP_CASCADE_POPDOWN:
+      gtk_popover_set_cascade_popdown (popover, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1524,6 +1531,10 @@ gtk_popover_get_property (GObject      *object,
       g_value_set_object (value, gtk_popover_get_child (popover));
       break;
 
+    case PROP_CASCADE_POPDOWN:
+      g_value_set_boolean (value, priv->cascade_popdown);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1674,6 +1685,13 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                            GTK_TYPE_WIDGET,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  properties[PROP_CASCADE_POPDOWN] =
+      g_param_spec_boolean ("cascade-popdown",
+                            P_("Cascade popdown"),
+                            P_("Wether the popover pops down after a child popover"),
+                            TRUE,
+                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
 
   signals[CLOSED] =
@@ -2047,6 +2065,31 @@ gtk_popover_popup (GtkPopover *popover)
   gtk_widget_show (GTK_WIDGET (popover));
 }
 
+static void
+cascade_popdown (GtkPopover *popover)
+{
+  GtkWidget *parent;
+
+  /* Do not trigger cascade close from non-modal popovers */
+  if (!gtk_popover_get_autohide (popover))
+    return;
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (popover));
+
+  while (parent)
+    {
+      if (GTK_IS_POPOVER (parent))
+        {
+          if (gtk_popover_get_cascade_popdown (GTK_POPOVER (parent)))
+            gtk_widget_hide (parent);
+          else
+            break;
+        }
+
+      parent = gtk_widget_get_parent (parent);
+    }
+}
+
 /**
  * gtk_popover_popdown:
  * @popover: a #GtkPopover
@@ -2061,6 +2104,8 @@ gtk_popover_popdown (GtkPopover *popover)
   g_return_if_fail (GTK_IS_POPOVER (popover));
 
   gtk_widget_hide (GTK_WIDGET (popover));
+
+  cascade_popdown (popover);
 }
 
 GtkWidget *
@@ -2223,3 +2268,40 @@ gtk_popover_get_offset (GtkPopover *popover,
   if (y_offset)
     *y_offset = priv->y_offset;
 }
+
+/**
+ * gtk_popover_set_cascade_popdown:
+ * @popover: A #GtkPopover
+ * @cascade_popdown: #TRUE if the popover should follow a child closing
+ *
+ * If @cascade_popdown is #TRUE, the popover will be closed when a child
+ * modal popover is closed. If #FALSE, @popover will stay visible.
+ **/
+void
+gtk_popover_set_cascade_popdown (GtkPopover *popover,
+                                 gboolean    cascade_popdown)
+{
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  if (priv->cascade_popdown != !!cascade_popdown)
+    {
+      priv->cascade_popdown = !!cascade_popdown;
+      g_object_notify (G_OBJECT (popover), "cascade-popdown");
+    }
+}
+
+/**
+ * gtk_popover_get_cascade_popdown:
+ * @popover: a #GtkPopover
+ *
+ * Returns whether the popover will close after a modal child is closed.
+ *
+ * Returns: #TRUE if @popover will close after a modal child.
+ **/
+gboolean
+gtk_popover_get_cascade_popdown (GtkPopover *popover)
+{
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  return priv->cascade_popdown;
+}
index a27fdf431a414b982ec82fc19997b45d19352232..9cb1208761001362b97db6254ebaea638be93842 100644 (file)
@@ -111,6 +111,11 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_popover_get_offset (GtkPopover *popover,
                                         int        *x_offset,
                                         int        *y_offset);
+GDK_AVAILABLE_IN_ALL
+void            gtk_popover_set_cascade_popdown (GtkPopover *popover,
+                                                 gboolean    cascade_popdown);
+GDK_AVAILABLE_IN_ALL
+gboolean        gtk_popover_get_cascade_popdown (GtkPopover *popover);
 
 GDK_AVAILABLE_IN_ALL
 void gtk_popover_set_default_widget (GtkPopover *popover,
index 2ea7fb9c3ae205051a0f55aec9f18c83b52b7a19..45228b508f7e7aca2e3f00a0095bf7a1c8d9cdf4 100644 (file)
@@ -809,6 +809,9 @@ _gtk_widget_grab_notify (GtkWidget *widget,
 
       gtk_event_controller_reset (controller);
     }
+
+  if (GTK_IS_NATIVE (widget))
+    gtk_widget_hide (widget);
 }
 
 static void